#include "xmlelement.h"
#include "transcoder.h"
#include "xmlelementiterator.h"
#include "xmltextiterator.h"

namespace MCCommon
{

// Name filter.
class XMLNameFilter: public xercesc::DOMNodeFilter
{
public:
    XMLNameFilter(const std::string& name)
    {
        fName = xercesc::XMLString::transcode( name.c_str() );    
    }
    
    XMLNameFilter()
    {
        fName = 0;
    }
    
    ~XMLNameFilter()
    {
        xercesc::XMLString::release(&fName);
    }    

    virtual FilterAction acceptNode(const xercesc::DOMNode* node) const
    {
        if(fName == 0 ||
            xercesc::XMLString::compareIString(node->getNodeName(), 
            fName) == 0)
        {
            return xercesc::DOMNodeFilter::FILTER_ACCEPT;
        }
        else
        {
            return DOMNodeFilter::FILTER_SKIP;
        }
    }
    
private:
    XMLCh* fName;
};

XMLElement::XMLElement()
:   fDomElement(0)
{
}

XMLElement::XMLElement
(
    xercesc::DOMElement* pDomElement
)
:   fDomElement(pDomElement)
{
}

XMLElement::XMLElement
(
    const XMLElement& element
)
{
    fDomElement = element.fDomElement;
}

XMLElement& 
XMLElement::operator = 
(
    const XMLElement& element
)
{
    XMLElement::XMLElement(element);
    
    return *this;
}

XMLElement::~XMLElement()
{
}

bool 
XMLElement::GetName
(
    std::string& name
)
{
    bool res( false );
    
    if( fDomElement )
    {
        const XMLCh *nameval = fDomElement->getTagName();
        if ( nameval )
        {
            res = true;
            name = A(nameval);
        }        
    }
    
    return res;
}

bool 
XMLElement::IsHaveAttribute
(
    const std::string &name
)
{
    bool res( false );

    if( fDomElement != 0)
    {
        res = fDomElement->hasAttribute( W(name) );
    }
        
    return res;
}

bool 
XMLElement::AddAttribute
(
    const std::string& name, 
    const std::string& value
)
{   
    bool res( false );

    if( fDomElement != 0 )
    {
        res = true;
        fDomElement->setAttribute( W(name), W(value) );
    }

    return res;
}

bool 
XMLElement::GetAttribute
(
    const std::string& name, 
    std::string& value
)
{
    bool res( false );

    if( fDomElement != 0)
    {
        const XMLCh* pAttrVal = fDomElement->getAttribute(W(name));
        if ( pAttrVal )
        {
            res = true;
            value = A(pAttrVal);
        }
    }

    return res;
} 

XMLElement 
XMLElement::AddElement
(
    const std::string& name
)
{
    xercesc::DOMElement* pDomEle = 0;
    
    if( fDomElement !=0 )
    {
        pDomEle = fDomElement->getOwnerDocument()->createElement(W(name));
        fDomElement->appendChild(pDomEle);       
    }

    return XMLElement(pDomEle);
}

XMLElement 
XMLElement::AddElement
(
    const std::string&name, 
    const std::string& text
)
{
    xercesc::DOMElement* pDomEle = 0;
    
    if( fDomElement !=0 )
    {
        pDomEle = fDomElement->getOwnerDocument()->createElement(W(name));
        fDomElement->appendChild(pDomEle);
        
        xercesc::DOMText* pText = fDomElement->getOwnerDocument()->createTextNode(W(text));
        pDomEle->appendChild(pText);        
    }

    return XMLElement(pDomEle);
} 

XMLElement 
XMLElement::GetElement
(
    const std::string& name
)
{
    if( fDomElement == 0 )
        return XMLElement(0);

    XMLNameFilter* filter = new XMLNameFilter(name);
    
    xercesc::DOMNodeIterator* iter = fDomElement->getOwnerDocument()->
        createNodeIterator(fDomElement, 
        xercesc::DOMNodeFilter::SHOW_ELEMENT, 
        filter, 
        true );
    
    XMLElementIterator xmlIter( iter, filter );

    XMLElement ele(0);
    if( xmlIter.HasMore() )
    {
        ele = xmlIter.Next();
    } 
    
    return ele;    
}

XMLElementIterator 
XMLElement::GetElementIterator
(
    const std::string& name
)
{
    if( fDomElement == 0 )
        return XMLElementIterator(0,0);

    XMLNameFilter* filter = new XMLNameFilter(name);
    
    xercesc::DOMNodeIterator* iter = fDomElement->getOwnerDocument()->
            createNodeIterator(fDomElement, xercesc::DOMNodeFilter::SHOW_ELEMENT, filter, true);
    
    return XMLElementIterator(iter,filter);    
}

bool 
XMLElement::SetText
(
    const std::string& text
)
{
    bool res(false);
    
    if ( fDomElement != 0 )
    {   
        res = true;

        xercesc::DOMText* pText = fDomElement->getOwnerDocument()->createTextNode(W(text));
        fDomElement->appendChild(pText);
    }

    return res;    
}

XMLTextIterator 
XMLElement::GetTextIterator
(
    const std::string& name
)
{
    if( fDomElement == 0 )
        return XMLTextIterator( 0, 0 );

    XMLNameFilter* filter = new XMLNameFilter(name);
    
    xercesc::DOMNodeIterator* iter = fDomElement->getOwnerDocument()->
            createNodeIterator(fDomElement, xercesc::DOMNodeFilter::SHOW_TEXT, filter, true);
    
    return XMLTextIterator(iter,filter);      
}

bool 
XMLElement::ToString( std::string& docString)
{
    bool res( false );

    if(fDomElement != 0 )
    {
        res = true;
    
        xercesc::DOMLSSerializer* serial = fDomElement->getOwnerDocument()->
            getImplementation()->createLSSerializer();
        XMLCh* pDocCh = serial->writeToString(fDomElement);
        serial->release();        
       
        docString = A(pDocCh); 
        xercesc::XMLString::release(&pDocCh);
    }

    return res;
}    

} // end of namespace MCXML_NAMESPACE.